﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SocialPlatforms;
using Yoozoo.Gta.Common;
using Yoozoo.Libs;
using Random = System.Random;

namespace Yoozoo.Modules.InnerCity
{
    public class CityBuildingTeam : IClass
    {
        // 对应一个建筑的建造
        private int id;
        
        // 负责建造的单位
        private List<CityUnit> members;
        
        // 建造的建筑物的周围格子
        private List<Vector2Int> targetPos;
        
        // 仓库周围的格子
        private List<Vector2Int> storagePos;

        // 此次建造需要的材料类型
        private List<int> resTypes;
        
        // 资源地周围的格子 ResType         index      grids
        private Dictionary<int, Dictionary<int, List<Vector2Int>>> resPos;

        private Random random;

        private Dictionary<int, Vector2Int> memberBuildPosDict;

        // BT == BuildTime
        private int minBT;
        private int maxBT;
        
        // CT == CollectTime
        private int minCT;
        private int maxCT;

        private int buildRate;

        public int ID
        {
            get => this.id;
        }

        public void Initialize(int id, List<CityUnit> members, List<Vector2Int> targetPos,
            List<Vector2Int> storagePos, List<int> resTypes, Dictionary<int, Dictionary<int, List<Vector2Int>>> resPos)
        {
            this.id = id;
            this.members = members;
            this.targetPos = targetPos;
            this.storagePos = storagePos;
            this.resTypes = resTypes;
            this.resPos = resPos;
            this.random = new Random(members.GetHashCode() - id);
            this.memberBuildPosDict = new Dictionary<int, Vector2Int>(members.Count);
            this.minBT = 2;
            this.maxBT = 5;
            this.buildRate = 50;
            this.minCT = 4;
            this.maxCT = 6;
        }

        public bool GetRandomResPoint(out int resType, out Vector2Int pos)
        {
            resType = ResourceType.None;
            pos = Vector2Int.zero;
            if (this.resTypes == null || this.resTypes.Count == 0)
                return false;
            
            if (this.resTypes.Count == 1)
                resType = this.resTypes[0];
            else
                resType = this.resTypes[this.random.Next(this.resTypes.Count)];

            List<Vector2Int> aroundPosList = null;
            if (this.resPos != null && this.resPos.ContainsKey(resType))
            {
                // rate走配置？
                var num = this.random.Next(100);
                if (num < 50)
                {
                    // 随机挑选出一片资源田
                    var ids = new List<int>();
                    foreach (var kvp in this.resPos[resType])
                        ids.Add(kvp.Key);

                    var id = ids[this.random.Next(ids.Count)];
                    aroundPosList = this.resPos[resType][id];
                }
                else
                    aroundPosList = this.storagePos;
            }
            else
                aroundPosList = this.storagePos;

            if (aroundPosList == null || aroundPosList.Count == 0)
                return false;

            if (aroundPosList.Count == 1)
                pos = aroundPosList[0];
            else
                pos = aroundPosList[this.random.Next(aroundPosList.Count)];

            return true;
        }

        public void DispatchWork()
        {
            foreach (var member in this.members)
                GiveBuildCommand(member);
        }

        public int Next(int value)
        {
            return this.random.Next(value);
        }

        public List<Vector3> GetRandomBuildPosPath(CityUnit unit)
        {
            var curPos = CityUnitMgr.Instance.VectorToGrid(unit.Position);
            return GetRandomBuildPosPath(unit, curPos);
        }

        public List<Vector3> GetRandomBuildPosPath(CityUnit unit, Vector2Int curPos)
        {
            var count = 0;
            while (true)
            {
                if (count++ > 100)
                    return new List<Vector3>();
                
                var endPos = RandomSelector.Select(GetFreeBuildPos(), 1, this.random)[0];
                var path = CityUnitMgr.Instance.FindPath(curPos, endPos);
                if (path == null || path.Count == 0)
                    continue;

                // 刷新占位
                this.memberBuildPosDict[unit.ID] = endPos;
                return path;
            }
        }

        public float GetRandomBuildTime()
        {
            return this.random.Next(this.minBT, this.maxBT) * 1.0f;
        }

        public bool IsBuildOrTakeObj()
        {
            return this.random.Next(100) < this.buildRate;
        }

        public void ExitBuildPos(CityUnit unit)
        {
            if (this.memberBuildPosDict.ContainsKey(unit.ID))
                this.memberBuildPosDict.Remove(unit.ID);
        }

        public float GetRandomCollectTime()
        {
            return this.random.Next(this.minCT, this.maxCT) * 1.0f;
        }

        public List<CityUnit> Dismiss()
        {
            foreach (var member in this.members)
                member.OnBuildTeamDismiss();

            return this.members;
        }

        public void AddMember(List<CityUnit> members)
        {
            this.members.AddRange(members);
            foreach (var member in members)
                GiveBuildCommand(member);
        }

        // 建造的建筑物位置发生改变
        public void OnBuildPosChange(List<Vector2Int> newPos)
        {
            this.targetPos = newPos;
            foreach (var member in this.members)
            {
                // 正在建造的人
                if (member.CurState == StateAction.Build)
                {
                    var curPos = CityUnitMgr.Instance.VectorToGrid(member.Position);
                    var atBuildPos = false;
                    foreach (var pos in newPos)
                    {
                        if (pos == curPos)
                        {
                            atBuildPos = true;
                            break;
                        }
                    }

                    // 如果旧的位置也在工地范围内
                    if (atBuildPos)
                        continue;
                    
                    // 前往新的位置建造
                    var path = GetRandomBuildPosPath(member, curPos);
                    member.ReWalkToBuild(path);
                }

                // 前往工地的，改变一下路径
                if (member.CurState == StateAction.Walk && member.MoveEndAction == StateAction.Build)
                {
                    var path = GetRandomBuildPosPath(member);
                    member.ReWalkToBuild(path);
                }
            }
        }

        public void OnStoragePosChange(List<Vector2Int> newPos)
        {
            this.storagePos = newPos;
        }

        public void OnResPosChange(int type, int index, List<Vector2Int> newPos)
        {
            var flag = false;
            foreach (var t in this.resTypes)
            {
                if (t == type)
                {
                    flag = true;
                    break;
                }
            }

            if (!flag)
                return;

            if (this.resPos == null)
                this.resPos = new Dictionary<int, Dictionary<int, List<Vector2Int>>>();
            
            Dictionary<int, List<Vector2Int>> dict;
            if (!this.resPos.TryGetValue(type, out dict))
            {
                dict = new Dictionary<int, List<Vector2Int>>();
                this.resPos.Add(type, dict);
            }

            List<Vector2Int> list;
            if (!dict.TryGetValue(index, out list))
            {
                list = new List<Vector2Int>();
                dict.Add(index, list);
            }

            list = newPos;
        }

        public void OnReset()
        {
            Dispose();
        }
        
        // 集合路径
        private List<List<Vector3>> FindGatherPath()
        {
            this.memberBuildPosDict.Clear();
            
            var startPos = new List<Vector2Int>(this.members.Count);
            foreach (var member in this.members)
            {
                var pos = CityUnitMgr.Instance.VectorToGrid(member.Position);
                foreach (var p in this.targetPos)
                {
                    if (p == pos)
                    {
                        this.memberBuildPosDict.Add(member.ID, p);
                        break;
                    }
                }
                
                startPos.Add(pos);
            }

            var vectorPath = new List<List<Vector3>>(this.members.Count);
            var index = 0;
            while (vectorPath.Count < this.members.Count)
            {
                var endPos = RandomSelector.Select(GetFreeBuildPos(), 1, this.random);
                var path = CityUnitMgr.Instance.FindPath(startPos[index], endPos[0]);
                if (path == null || path.Count == 0)
                    continue;
                
                vectorPath.Add(path);
                this.memberBuildPosDict[this.members[index].ID] = endPos[0];
                index++;
            }

            return vectorPath;
        }

        private List<Vector2Int> GetFreeBuildPos()
        {
            if (this.memberBuildPosDict.Count == 0)
                return this.targetPos;

            // n^2
            var ret = new List<Vector2Int>(this.targetPos.Count - this.memberBuildPosDict.Count);
            foreach (var pos in targetPos)
                foreach (var kvp in this.memberBuildPosDict)
                    if (pos != kvp.Value)
                        ret.Add(pos);

            return ret;
        }

        private bool IsMember(CityUnit unit)
        {
            foreach (var member in this.members)
                if (member.ID == unit.ID)
                    return true;

            return false;
        }

        // 让unit开始建造
        private void GiveBuildCommand(CityUnit unit)
        {
            var pos = CityUnitMgr.Instance.VectorToGrid(unit.Position);
            var atBuildPos = false;
            foreach (var _pos in this.targetPos)
            {
                if (_pos == pos)
                {
                    atBuildPos = true;
                    break;
                }
            }

            if (!atBuildPos)
            {
                var path = GetRandomBuildPosPath(unit, pos);
                unit.WalkToBuild(path, this);
                return;
            }

            var posIsBusy = false;
            foreach (var kvp in this.memberBuildPosDict)
            {
                if (pos == kvp.Value)
                {
                    // 该位置已经被占用
                    posIsBusy = true;
                    break;
                }
            }

            if (posIsBusy)
            {
                var path = GetRandomBuildPosPath(unit, pos);
                unit.WalkToBuild(path, this);
                return;
            }

            this.memberBuildPosDict[unit.ID] = pos;
            unit.Build(this);
        }

        private void Dispose()
        {
            this.id = 0;
            this.members = null;
            this.targetPos = null;
            this.storagePos = null;
            this.resTypes = null;
            this.resPos = null;
            this.memberBuildPosDict = null;
            this.minBT = 0;
            this.maxBT = 0;
            this.minCT = 0;
            this.maxCT = 0;
            this.buildRate = 0;
        }
    }
}